#ifndef TD_CREEP_H_
#define TD_CREEP_H_

/************************************************************************/
/* STL                                                                  */
/************************************************************************/
#include <vector> 
#include <map>

/************************************************************************/
/* Core                                                                 */
/************************************************************************/
#include "Core/Coord2D.h"
#include "Core/BaseEntity.h"
#include "Core/Timer.h"
#include "Core/Matrix2D.h"
#include "Core/Utils.h"

/************************************************************************/
/* GUI                                                                  */
/************************************************************************/
#include "GUI/Bars/HealthBar.h"

/************************************************************************/
/* RESOURCES                                                            */
/************************************************************************/
#include "Resources/Tiles/Tileset.h"

/************************************************************************/
/* GAME                                                                 */
/************************************************************************/
#include "Game/GameCore.h"
#include "Game/Waveinfo.h"
#include "Game/Animations/AnimationSet.h"
#include "Game/Factories/AnimationSetFactory.h"
#include "Game/Tilemaps/TerrainTilemap.h"

using namespace std;
using namespace TD_GUI;
using namespace TD_Resources;

namespace TD_Game {
	
	typedef enum {
		NORTH,
		SOUTH,
		EAST,
		WEST
	} baseMarioDirection;



	class BaseMario : public BaseEntity {
	
	protected:

		/************************************************************************/
		/* Default definitions                                                  */
		/************************************************************************/
		static const unsigned int m_waitingTime;
		static const unsigned int m_turnDownTime;
		static const unsigned int m_defaultMaxLife;
		static const float m_defaultBaseMarioSpeed;
	
		/** Defines the possible baseMario actions.*/
		typedef enum {
			pipeWarping,
			pipeWaiting,
			jumpingArising,
			idleUp,
			idleDown,
			idleLeft,
			idleRight,
			walkingUp,
			walkingDown,
			walkingLeft,
			walkingRight,
			dying
		} baseMarioActions;
		
		/** Position updating will be twice as slow as rendering updating.*/
		float m_updateCount;
		float m_tx;
		float m_ty;
		float m_jumpingForce;
		float m_jumpingSpeed;
		int m_waitingTicks;

		/** BaseMario starting direction */
		baseMarioDirection m_baseMarioDirection;
		
		/** If the baseMario is dead*/
		bool m_isDead;

		/** If the baseMario is dead*/
		bool m_isDying;

		/** The current baseMario speed.*/
		float m_maxBaseMarioSpeed;
		float m_baseMarioSpeed;
		int m_pathDeviant;

		/** Slow debuff*/
		mutable unsigned int m_slowTick;
		mutable unsigned int m_slowTime;
		mutable float m_slowAmount;
		
		mutable unsigned int m_tick;
		
		Coord2D m_nextWaypoint;
		Coord2D m_dispVector;

		/** BaseMario life variable*/
		int m_maxLife;
		mutable int m_currLife;

		/** Current terrain.*/
		TerrainTilemap *m_pTerrain;

		/** The terrain written in path matrix form, calculated by the tilemap.*/
		Matrix2D *m_pPathMatrix;
		
		Coord2D m_pathSize;
		
		/** Actions*/
		mutable baseMarioActions m_lastAction;
		mutable baseMarioActions m_currAction;
		int m_lastIndex_i;
		int m_lastIndex_j;


		/** The animation set.*/
		AnimationSet *m_pAnimationSet;

		/** Internal timer, used for updating purposes.*/
		Timer m_internalTimer;
		
		WaveInfo m_waveInfo;

		unsigned int m_baseMarioGold;

		HealthBar *m_pHealthBar;

		shared_ptr<SDLSound> m_pJumpSound;
		shared_ptr<SDLSound> m_pBossSound;

		/************************************************************************/
		/* Protected functions                                                  */
		/************************************************************************/
		virtual void loadResources(marioTypes mType) = 0;
		void updateDirection(int i, int j);
	
	public:
		
		/************************************************************************/
		/* Constructors                                                         */
		/************************************************************************/
		
		//Default constructor
		BaseMario();
		
		//Copy constructor

		//Assignment constructor

		//Initialization constructor
		BaseMario(const WaveInfo &gWaveInfo, const Coord2D &g_position, TerrainTilemap * const terrainTilemap, int pathDeviant = 0, baseMarioDirection cDirection = WEST);

		~BaseMario();

		/************************************************************************/
		/* Access functions                                                     */
		/************************************************************************/
		inline void receiveDamage(unsigned int damage) const {
			m_currLife -= damage;
			m_pHealthBar->setHealth(m_currLife/static_cast<float>(m_maxLife));
			if(m_currLife <= 0) {
				m_currAction = dying;
			}
		}

		inline void setPosition(const Coord2D & g_position) {
			BaseEntity::setPosition(g_position);
			m_pHealthBar->setPosition(m_position - Coord2D(10, 23));
		}

		inline bool isDead() const {
			return(m_isDead);
		}
		inline bool isDying() const {
			return(m_isDying);
		}

		inline unsigned int getLife() const  {
			return(m_currLife);
		}

		inline unsigned int getGold() const {
			return (m_baseMarioGold);
		}

		inline virtual void addSlowDebuff(unsigned int slowTime, float slowPercentage) const
		{

		}

		inline bool isWalking() const {
			if(m_currAction == walkingDown || m_currAction == walkingLeft 
				|| m_currAction == walkingRight || m_currAction == walkingUp)
				return true;
			return false;
		}

		/************************************************************************/
		/* Functionalities                                                      */
		/************************************************************************/
		void update(unsigned int deltaTime);
		void render(SDL_Surface *const g_destSurface, unsigned int deltaTime);
	};

}

#endif